施工廠商到店家安裝相機時,除了數量與位置要正確,相機的角度與涵蓋範圍也要符合事前的模擬,所以現場的施工人員要能一次看到所有相機的即時畫面,逐一確認。IP cam 都有內建 Web UI 可以觀看串流,但對非資訊專長的施工人員來說,逐支登入相機的 Web UI 難度太高,因此我們在 edge server 上做了一面多相機的即時監控牆 — Camera Grid。門市現場除了 edge server,還會安裝一台顯示器,它正式上線後的工作是顯示 Day 01 提過的 Drive-thru Real-Time Dashboard;相機安裝階段還沒有數據可看,這台顯示器就先借來當監控牆。先列出基本需求:
這面監控牆分成三層:最底下是 kiosk 顯示層,Ubuntu Frame 加 Chromium 讓 edge server 不裝桌面環境就能全螢幕顯示網頁;中間是串流層,MediaMTX 把 RTSP 轉成瀏覽器能播放的協定;最上層是裝置管理,Camera Manager 維護相機清單並彙整狀態資料。以下依序說明。

實線是影像與資料的流向,虛線是 Camera Manager 發出的控制指令;顯示器接在 edge server 上。
加裝桌面環境當然可行,但我們希望 edge server 在沒有登入、也沒有任何人工操作 (真實環境中沒有滑鼠鍵盤) 的狀況下,開完機就直接顯示指定的網頁。
Canonical 在 2021 年 10 月推出的 Ubuntu Frame,正是為這種需求設計的顯示伺服器,專門服務 kiosk、數位看板這類「一台機器只跑一個全螢幕應用」的場景。它底層建構在 Mir (Canonical 開發的 Wayland compositor 函式庫) 之上,對應用程式提供標準的 Wayland 介面;以 snap 的形式發布,不需要安裝桌面環境,也沒有工作列、視窗標題列或切換視窗的快捷鍵,開機後什麼都不會顯示,等著應用程式把畫面填滿。安裝後設定 daemon=true,Ubuntu Frame 就會註冊成系統服務,每次開機在無人登入的情況下自動啟動並接管顯示輸出。
有了顯示伺服器,接著要決定用哪個瀏覽器來顯示網頁。Canonical 官方教學搭配的是輕量的 WPE WebKit,但 Chromium 的網頁相容性與除錯工具都成熟得多,所以我們選擇 Chromium。
安裝順序是先 Ubuntu Frame 再 Chromium:前者接管顯示輸出,後者是掛在它上面的唯一一個應用程式。中間那段 screenshot 指令是驗證用的,edge server 通常不在手邊,遠端擷取一張畫面就能確認輸出正常。
sudo snap install ubuntu-frame
sudo snap set ubuntu-frame daemon=true
# 設定顯示器輸出的解析度與縮放
sudo snap set ubuntu-frame display="
layouts:
default:
cards:
- card-id: 0
HDMI-A-1:
mode: 1920x1080@60.0
scale: 1
group: 0
"
# screenshot 工具需要這個 plug 才能連上 Frame
sudo snap connect ubuntu-frame:wayplug
# 擷取螢幕畫面,在支援 imgcat 的終端機直接檢視
sudo mv $(sudo ubuntu-frame.screenshot) ss.png && cat ss.png | imgcat
# 安裝 Chromium
sudo snap install chromium
sudo snap connect chromium:wayland
sudo snap connect chromium:network-bind
sudo snap set chromium daemon=true
# 設定 Chromium 要顯示的網址,9527 是 Camera Grid 網頁的 port
sudo snap set chromium url=http://localhost:9527/
Chromium snap 的 daemon 與 url 這兩個設定並沒有記載在官方文件中,是翻閱 chromium snap 的打包設定之後找到的用法,我們已在正式環境長期使用。
這個組合的好處是整套顯示功能只由兩個 snap 組成:沒有桌面環境要維護,也不用擔心螢幕保護、自動更新提示或系統通知跳出來蓋住畫面。施工廠商把顯示器接上 edge server 開機,等一分鐘左右整面監控牆就會填滿所有相機的即時畫面 — 剩下調整角度與變焦的工作,交給 Camera Grid 處理。
顯示什麼內容完全由 url 這一個設定決定,所以門市驗收完、要換成 Drive-thru Real-Time Dashboard 時,kiosk 這一層不用動:
# 門市上線,同一台顯示器從監控牆換成營運看板
sudo snap set chromium url=https://<dashboard-url>/
sudo snap restart chromium.daemon
這兩個 snap 我們踩過的坑不少:版本並不是越新越好,兩者的組合也可能有相容性問題,所以測試過後要把版本都鎖定,塞進 Day 05 提到的那支安裝 USB,在 autoinstall 階段離線安裝:
# 辦公室,有網路的機器:下載並打包,以 Chromium 為例
snap download chromium
assert_file=$(ls | grep "chromium_.*\.assert")
snap_file=$(ls | grep "chromium_.*\.snap")
current_date=$(date +%Y%m%d)
tar -czvf "chromium_snap_$current_date.tgz" "$assert_file" "$snap_file"
打包好的 .tgz 跟著 ISO 一起進 USB,產線上還原:
# 產線,離線的出貨機:還原並安裝
tar -xzvf chromium_snap_20231116.tgz
assert_file=$(ls | grep "chromium_.*\.assert")
snap_file=$(ls | grep "chromium_.*\.snap")
sudo snap ack "$assert_file"
sudo snap install "$snap_file"
snap 預設會不定時自動更新,要讓版本真的鎖住,還得關閉自動 refresh (snapd 2.58 起支援 --hold):
# 鎖定特定 package,例如 ubuntu-frame 與 Chromium
sudo snap refresh --hold=forever ubuntu-frame chromium
# 鎖定整個系統的所有 snap
sudo snap refresh --hold=forever
瀏覽器不支援 RTSP,中間需要一個轉封裝的角色,這正是 Day 07 介紹過的 MediaMTX 的工作:它把每支相機的 RTSP 以 source proxy 的方式拉進來 (由 MediaMTX 主動連上相機取流,相機端不必改設定),每支相機對應 MediaMTX 上的一條 path,同一條 path 可同時以 HLS 與 WebRTC 對外提供,前端把播放來源指向 http://<edge-ip>:8888/<camId>/index.m3u8,用 ReactPlayer (React 生態系的播放器元件) 就能播放。
嵌入頁面的部分並不複雜,ReactPlayer 遇到 .m3u8 的來源會自動載入 hls.js 處理,所以沒有原生 HLS 支援的 Chromium 也能播放。骨架大致如下 (以 v3 的 API 為例,v2 的 url prop 在 v3 改名為 src):
import ReactPlayer from "react-player";
// cams 是相機清單,來自 Camera Manager 產出的 JSON (下一節)
function CameraGrid({ cams }) {
return (
<div className="grid">
{cams.map((cam) => (
<ReactPlayer
key={cam.id}
src={`http://${location.hostname}:8888/${cam.id}/index.m3u8`}
playing
muted
width="100%"
height="100%"
/>
))}
</div>
);
}
比較容易被忽略的是 Chromium 的自動播放政策:沒有使用者互動的頁面只允許靜音影片自動播放,所以 muted 必須設定,否則 kiosk 開機後畫面會停在第一幀。
相機清單不能寫死:一間門市裝幾支相機、每支的 IP 由 DHCP 配到哪,都是到了現場才知道。所以 edge server 上有一支常駐的管理程式 Camera Manager,定期做三件事:
Camera Grid 的網頁本身也由 edge server 提供,前端 fetch 這份 JSON 後,依相機數量自動決定版面的欄列數,把沒 ready 的相機標紅,之後每 60 秒重抓一次 JSON 更新狀態;至於變焦,按鈕呼叫的是 Camera Manager 的 API,由它透過 ONVIF 對相機下指令。
回顧這面監控牆的三層:Ubuntu Frame 加 Chromium 撐起不用桌面環境的 kiosk 顯示層,MediaMTX 把 RTSP 轉成瀏覽器播得動的 HLS,Camera Manager 維護相機清單與狀態。施工廠商把顯示器接上 edge server,開機就能看到所有相機的即時畫面與網路狀態,全程沒有人登入這台機器,也沒有桌面環境要維護。這套組合的前提是版本鎖定:snap 的自動更新造成過相容性問題,所有 snap 都必須測試後鎖版、離線安裝 — 代價是安全性更新也一併被擋下,後續的更新必須改由自己的部署機制接手。
本系列由 Berry AI 工程團隊出品。更多工程實戰紀錄都在 Berry AI 技術部落格。